﻿using System;
using System.Collections.Generic;
using System.Text;

namespace CommandLineParser
{
    public class CommandLineComponent
    {
        public bool IsFullOption { get; private set; }

        public bool IsAbbreviatedOption { get; private set; }

        public bool IsOption => IsFullOption || IsAbbreviatedOption;

        public string Value { get; private set; }

        public bool ClungValue { get; internal set; }

        internal CommandLineComponent(char abbreviation)
        {
            IsAbbreviatedOption = true;
            Value = abbreviation.ToString();
        }

        internal CommandLineComponent(bool isFullOption, string value)
        {
            IsFullOption = isFullOption;
            Value = value;
        }
    }


    public class CommandLineDecomposer
    {

        public static IList<CommandLineComponent> Decompose(string commandLine, IList<string> errList)
        {
            //检查参数
            if (commandLine == null)
                throw new ArgumentNullException(nameof(commandLine));

            //准备状态
            CommandLineParserState state = CommandLineParserState.None;

            //准备工具变量
            var reader = new ReaderHelper(commandLine);
            var builder = new StringBuilder();

            //结果
            List<CommandLineComponent> result = new List<CommandLineComponent>();

            //准备工作变量
            bool working = true;
            CommandLineComponent currentOption = null;

            //循环阅读
            while (working)
            {
                bool endOfString = reader.EndOfString;
                char c = endOfString ? ' ' : reader.ReadChar();
                switch (state)
                {
                    //等待选项或值状态
                    case CommandLineParserState.None:
                        //读取结束
                        if (endOfString)
                        {
                            working = false;
                            break;
                        }
                        //空格
                        if (c == ' ')
                            break;
                        //第一个横线
                        if (c == '-')
                        {
                            state = CommandLineParserState.OptionInitialized;
                            break;
                        }
                        //直接开始数值记录
                        reader.Rewind(1);
                        state = CommandLineParserState.ValueInitialized;
                        currentOption = null;
                        break;
                    //等待命令
                    case CommandLineParserState.OptionInitialized:
                        //读取结束
                        if (endOfString)
                        {
                            errList?.Add("unexpected end of string.");
                            working = false;
                            break;
                        }
                        //不支持的字符
                        if (c == ' ')
                        {
                            errList?.Add($"unexpected space at {reader.Position}.");
                            working = false;
                            break;
                        }
                        //第二个横线
                        if (c == '-')
                        {
                            state = CommandLineParserState.OptionReading;
                            builder.Clear();
                            break;
                        }
                        //缩写命令
                        reader.Rewind(1);
                        state = CommandLineParserState.OptionAbbrReading;
                        builder.Clear();
                        currentOption = null;
                        break;
                    //读取命令
                    case CommandLineParserState.OptionReading:
                        //空格：阅读结束
                        if (c == ' ')
                        {
                            //获取内容
                            string name = builder.ToString();
                            currentOption = new CommandLineComponent(true, name);
                            //添加到列表
                            result.Add(currentOption);
                            //更新状态
                            state = CommandLineParserState.None;
                            break;
                        }
                        //冒号：值
                        if (c == ':')
                        {
                            //获取内容
                            string name = builder.ToString();
                            currentOption = new CommandLineComponent(true, name);
                            currentOption.ClungValue = true;
                            //添加到列表
                            result.Add(currentOption);
                            //更新状态
                            state = CommandLineParserState.ValueInitialized;
                            builder.Clear();
                            break;
                        }
                        //添加到builder
                        builder.Append(c);
                        break;
                    case CommandLineParserState.OptionAbbrReading:
                        //空格：阅读结束
                        if (c == ' ')
                        {
                            state = CommandLineParserState.None;
                            break;
                        }
                        //冒号：值
                        if (c == ':')
                        {
                            if (currentOption != null)
                                currentOption.ClungValue = true;
                            state = CommandLineParserState.ValueInitialized;
                            builder.Clear();
                            break;
                        }
                        currentOption = new CommandLineComponent(c);
                        //添加到列表
                        result.Add(currentOption);
                        break;
                    case CommandLineParserState.ValueInitialized:
                        //空格
                        if (c == ' ')
                        {
                            state = CommandLineParserState.None;
                            break;
                        }
                        builder.Clear();
                        //双引号：转义字符串
                        if (c == '"')
                        {
                            state = CommandLineParserState.ValueEscapedReading;
                            break;
                        }
                        //正常读取
                        reader.Rewind(1);
                        state = CommandLineParserState.ValuePlaneReading;
                        break;
                    case CommandLineParserState.ValuePlaneReading:
                        //空格：读取结束
                        if (c == ' ')
                        {
                            string value = builder.ToString();
                            //添加到列表
                            result.Add(new CommandLineComponent(false, value));
                            state = CommandLineParserState.None;
                            break;
                        }
                        //读取
                        builder.Append(c);
                        break;
                    case CommandLineParserState.ValueEscapedReading:
                        //双引号：读取结束
                        if (endOfString || c == '"')
                        {
                            string value = builder.ToString();
                            //添加到列表
                            result.Add(new CommandLineComponent(false, value));
                            state = CommandLineParserState.None;
                            if (endOfString)
                            {
                                //throw new CommandLineParserException();
                                working = false;
                            }
                            break;
                        }
                        //右斜线：转义：
                        if (c == '\\')
                        {
                            state = CommandLineParserState.ValueEscaped;
                            break;
                        }
                        //读取
                        builder.Append(c);
                        break;
                    case CommandLineParserState.ValueEscaped:
                        //读取结束
                        if (endOfString)
                        {
                            errList?.Add("unexpected end of string.");
                            working = false;
                            break;
                        }
                        //右斜线：转义自身
                        if (c == '\\')
                        {
                            builder.Append('\\');
                            break;
                        }
                        //其他字符
                        builder.Append(c);
                        break;
                }
            }

            return result;
        }

        private enum CommandLineParserState
        {
            None,
            OptionInitialized,
            OptionReading,
            OptionAbbrReading,
            ValueInitialized,
            ValuePlaneReading,
            ValueEscapedReading,
            ValueEscaped,
        }

        private class ReaderHelper
        {
            private string baseString;
            public int Position { get; private set; }
            public int Length => baseString.Length;

            public char ReadChar()
            {
                return baseString[Position++];
            }

            public bool EndOfString
            {
                get { return Position >= baseString.Length; }
            }

            public void Rewind()
            {
                Position = 0;
            }

            public void Rewind(int steps)
            {
                Position -= steps;
            }

            public ReaderHelper(string s)
            {
                if (s == null)
                    throw new ArgumentNullException();
                baseString = s;
            }
        }
    }


}
